
package jwww.handlers;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.regex.Pattern;

import jwww.service.Page;
import jwww.service.Service;
import jwww.util.*;

import org.apache.log4j.Logger;

public class SimpleServer implements Service
{
  String fsRoot = null;

  Pattern cgi = null;

  Logger logger = null;

  @Override
  public boolean initialize()
  {
    logger  = Logger.getLogger("JWWW");

    fsRoot = System.getenv("JWWW_ROOT");
    if (fsRoot == null)
    {
      logger.fatal("JWWW_ROOT must be set!");
      return false;
    }

    // CGI is *.cgi.py, *.cgi.sh, etc.
    cgi = Pattern.compile(".*\\.cgi\\..*");

    logger.info("initialized");
    logger.info("root: " + fsRoot);

    return true;
  }

  @Override
  public Page get(String query)
  {
    logger.info("get: " + query);

    Page result = null;

    if (query.equals("/"))
      query = "/index.html";

    if (query.equals("/favicon.ico"))
      return Page.notFound(query);

    if (query.endsWith(".html"))
      result = getText(query);
    else if (query.indexOf(".cgi.") != -1)
      result = runCGI(query);
    else
      result = getFile(query);

    return result;
  }

  Page getText(String filename)
  {
    File file = new File(fsRoot + filename);
    logger.info("text: " + file);
    String text;
    try
    {
      text = TextReader.read(file);
    }
    catch (FileNotFoundException e)
    {
      logger.info("file not found: " + file);
      return Page.notFound(filename);
    }
    Page result = new Page(200, new Date(), text);
    return result;
  }

  Page runCGI(String command)
  {
    String[] cmd_args = command.split("\\?");
    String   cmd  = cmd_args[0];
    String[] args;
    if (cmd_args.length > 1)
      args = cmd_args[1].split("&");
    else
      args = new String[0];

    File program = new File(fsRoot + cmd);
    String cmdline = program + " " + StringUtil.concat(args);
    logger.info("run: " + cmdline);

    sanitize(args);

    if (!program.canExecute())
      return new Page("not executable: " + program);

    QuickProcess qp = new QuickProcess(program.toString());
    qp.setenv(args);
    qp.run();
    String text = qp.output();
    Page result = new Page(200, new Date(), text);
    return result;
  }

  void sanitize(String[] args)
  {
    for (int i = 0; i < args.length; i++)
    {
      logger.trace("sanitize: " + args[i]);
      args[i] = args[i].replaceAll("%2F", "/");
      args[i] = args[i].replaceFirst("\\+", "");
      logger.trace("sanitize: " + args[i]);
    }
  }

  Page getFile(String filename)
  {
    File file = new File(fsRoot + filename);
    logger.info("file: " + file);

    if (!file.canRead())
    {
      logger.info("file not readable: " + file);
      return Page.notFound(filename);
    }
    Page result = new BinaryFile(file.toString());
    return result;
  }

  @Override
  public Page head(String query)
  {
    Logger logger = Logger.getLogger("JWWW");
    logger.info("head: " + query);

    return null;
  }
}
